﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using BrightIdeasSoftware;
using Ooaavee.Support;

namespace DevelopersTestPad.Worksheets.DotNet
{
    public partial class ReflectionTreeView : UserControl
    {
        public ReflectionTreeView()
        {
            InitializeComponent();
            InitializeTreeListView();
        }

        /// <summary>
        /// Gets the TreeListView control.
        /// </summary>
        private TreeListView Tree { get { return treeListView; } }

        /// <summary>
        /// Initializes the TreeListView component.
        /// </summary>
        private void InitializeTreeListView()
        {
            Tree.CanExpandGetter = CanExpandGetter;
            Tree.ChildrenGetter = ChildrenGetter;
            olvColumnName.ImageGetter = ImageGetter;

            TreeListView.TreeRenderer renderer = Tree.TreeColumnRenderer;
            renderer.IsShowLines = false;              
         
            
        }

        /// <summary>
        /// Adds a reflected object into the ReclectionTreeView.
        /// </summary>
        /// <param name="reflected">The reflected object to add.</param>
        public void Add(Reflector.ReflectedObject reflected)
        {
            ReflectedObjectDataWrapper model = new ReflectedObjectDataWrapper { Object = reflected };

            Tree.AddObject(model);
        }

        /// <summary>
        /// Gets the image index for nodes.
        /// </summary>
        private object ImageGetter(object x)
        {
            if (x is ReflectedObjectDataWrapper)
            {
                return 0;
            }
            if (x is NonPublicMembersHeader)
            {
                return 0;
            }
            if (x is ReflectedPropertyDataWrapper)
            {
                if (((ReflectedPropertyDataWrapper) x).IsPublic)
                {
                    return 3;                    
                }
                else
                {
                    return 4;                    
                }
            }
            if (x is ReflectedFieldDataWrapper)
            {
                if (((ReflectedFieldDataWrapper)x).IsPublic)
                {
                    return 0;
                }
                else
                {
                    return 1;
                }
            }
            return -1;
        }

        /// <summary>
        /// Is the node expandable?
        /// </summary>
        private bool CanExpandGetter(object x)
        {
            // The root nodes is always expandable.
            if (x is ReflectedObjectDataWrapper)
            {
                return true;
            }

            // Non-public members header node is always expandable.
            if (x is NonPublicMembersHeader)
            {
                return true;
            }

            // The property node is expandable if the property have any members.
            if (x is ReflectedPropertyDataWrapper)
            {
                ReflectedPropertyDataWrapper model = (ReflectedPropertyDataWrapper)x;
                if (model.Property.PublicFields.Count > 0 ||
                    model.Property.PublicProperties.Count > 0 ||
                    model.Property.NonPublicFields.Count > 0 ||
                    model.Property.NonPublicProperties.Count > 0)
                {
                    return true;
                }
            }

            // The field node is expandable if the field have any members.
            if (x is ReflectedFieldDataWrapper)
            {
                ReflectedFieldDataWrapper model = (ReflectedFieldDataWrapper)x;
                if (model.Field.PublicFields.Count > 0 ||
                    model.Field.PublicProperties.Count > 0 ||
                    model.Field.NonPublicFields.Count > 0 ||
                    model.Field.NonPublicProperties.Count > 0)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Lazy load children nodes.
        /// </summary>
        private IEnumerable ChildrenGetter(object x)
        {
            ArrayList childrens = new ArrayList();

            if (x is ReflectedObjectDataWrapper)
            {
                ReflectedObjectDataWrapper model = x as ReflectedObjectDataWrapper;

                childrens.AddRange(GetChildrens(model.Object.PublicFields, model.Object.PublicProperties, true));

                if (model.Object.NonPublicFields.Count > 0 || model.Object.NonPublicProperties.Count > 0)
                {
                    childrens.Add(new NonPublicMembersHeader { Object = model.Object });
                }
            }

            if (x is NonPublicMembersHeader)
            {
                NonPublicMembersHeader model = x as NonPublicMembersHeader;

                if (model.Object != null)
                {
                    childrens.AddRange(GetChildrens(model.Object.NonPublicFields, model.Object.NonPublicProperties, false));
                }
                if (model.Property != null)
                {
                    childrens.AddRange(GetChildrens(model.Property.NonPublicFields, model.Property.NonPublicProperties, false));
                }
                if (model.Field != null)
                {
                    childrens.AddRange(GetChildrens(model.Field.NonPublicFields, model.Field.NonPublicProperties, false));
                }
            }

            if (x is ReflectedPropertyDataWrapper)
            {
                ReflectedPropertyDataWrapper model = x as ReflectedPropertyDataWrapper;

                childrens.AddRange(GetChildrens(model.Property.PublicFields, model.Property.PublicProperties, true));

                if (model.Property.NonPublicFields.Count > 0 || model.Property.NonPublicProperties.Count > 0)
                {
                    childrens.Add(new NonPublicMembersHeader { Property = model.Property });
                }
            }

            if (x is ReflectedFieldDataWrapper)
            {
                ReflectedFieldDataWrapper model = x as ReflectedFieldDataWrapper;

                childrens.AddRange(GetChildrens(model.Field.PublicFields, model.Field.PublicProperties, true));

                if (model.Field.NonPublicFields.Count > 0 || model.Field.NonPublicProperties.Count > 0)
                {
                    childrens.Add(new NonPublicMembersHeader { Field = model.Field });
                }
            }

            return childrens;
        }

        private static ArrayList GetChildrens(Collection<Reflector.ReflectedField> fields, Collection<Reflector.ReflectedProperty> properties, bool isPublic)
        {
            ArrayList childrens = new ArrayList();

            foreach (Reflector.ReflectedField field in Sort(fields))
            {
                childrens.Add(new ReflectedFieldDataWrapper { Field = field, IsPublic = isPublic });
            }

            foreach (Reflector.ReflectedProperty property in Sort(properties))
            {
                childrens.Add(new ReflectedPropertyDataWrapper { Property = property, IsPublic = isPublic });
            }

            return childrens;
        }

        /// <summary>
        /// Return fiels as sorted.
        /// </summary>
        private static IEnumerable Sort(Collection<Reflector.ReflectedField> fields)
        {
            var f = new List<Reflector.ReflectedField>(fields);
            f.Sort((f1, f2) => String.Compare(f1.Name, f2.Name, StringComparison.CurrentCulture));
            return f;
        }

        /// <summary>
        /// Return properties as sorted.
        /// </summary>
        private static IEnumerable Sort(Collection<Reflector.ReflectedProperty> properties)
        {
            var p = new List<Reflector.ReflectedProperty>(properties);
            p.Sort((p1, p2) => String.Compare(p1.Name, p2.Name, StringComparison.CurrentCulture));
            return p;
        }

        /// <summary>
        /// The model base class.
        /// </summary>
        private abstract class ReflectionDataWrapperBase
        {
            public abstract string Name { get; }
            public abstract string Value { get; }
            public abstract string Type { get; }
        }

        /// <summary>
        /// The reflected object in the model.
        /// </summary>
        private sealed class ReflectedObjectDataWrapper : ReflectionDataWrapperBase
        {
            public Reflector.ReflectedObject Object { set; get; }

            public override string Name
            {
                get { return "{" + Object.Type.FullName + "}"; }
            }

            public override string Value
            {
                get { return Object.Value.DisplayValue; }
            }

            public override string Type
            {
                get { return Object.Type.FullName; }
            }
        }

        /// <summary>
        /// The Non-public members header in the model.
        /// </summary>
        private sealed class NonPublicMembersHeader : ReflectionDataWrapperBase
        {
            public Reflector.ReflectedObject Object { set; get; }
            public Reflector.ReflectedProperty Property { set; get; }
            public Reflector.ReflectedField Field { set; get; }

            public override string Name
            {
                get { return "Non-Public members"; }
            }

            public override string Value
            {
                get { return string.Empty; }
            }

            public override string Type
            {
                get { return string.Empty; }
            }
        }

        /// <summary>
        /// The reflected property in the model.
        /// </summary>
        private sealed class ReflectedPropertyDataWrapper : ReflectionDataWrapperBase
        {
            public Reflector.ReflectedProperty Property { set; get; }
            public bool IsPublic { set; get; }

            public override string Name
            {
                get { return Property.Name; }
            }

            public override string Value
            {
                get { return Property.Value.DisplayValue; }
            }

            public override string Type
            {
                get { return Property.Type.FullName; }
            }
        }

        /// <summary>
        /// The reflected field in the model.
        /// </summary>
        private sealed class ReflectedFieldDataWrapper : ReflectionDataWrapperBase
        {
            public Reflector.ReflectedField Field { set; get; }
            public bool IsPublic { set; get; }

            public override string Name
            {
                get { return Field.Name; }
            }

            public override string Value
            {
                get { return Field.Value.DisplayValue; }
            }

            public override string Type
            {
                get { return Field.Type.FullName; }
            }
        }
    }
}
